<?php
define('DEBUG', 'on');
define("WEBPATH", str_replace("\\","/", __DIR__));
define("APPSPATH", __DIR__ . '/../apps');
require __DIR__ . '/../libs/lib_config.php';

class WebSocket extends Swoole\Protocol\WebSocket
{
    protected $message;
    // static public $userinfo_table;
    protected $clientid_userid_table;
    protected $userid_clientid_table;

    public function __construct()
    {
        parent::__construct();

        //创建一个swoole_table。存储客户端信息
        /*$userinfo_table = new swoole_table(1024);
        $userinfo_table->column('userid', swoole_table::TYPE_INT);
        $userinfo_table->column('username', swoole_table::TYPE_STRING, 20);
        $userinfo_table->create();
        self::$userinfo_table = $userinfo_table;*/

        //一个clientid， 只能有一个userid
        $clientid_userid_table = new swoole_table(1024);
        $clientid_userid_table->column('userid', swoole_table::TYPE_INT);
        $clientid_userid_table->create();
        $this->clientid_userid_table = $clientid_userid_table;

        //一个userid， 可以有多个client_id. 这里用ids形式表示
        $userid_clientid_table = new swoole_table(1024);
        $userid_clientid_table->column('client_ids', swoole_table::TYPE_STRING, 100);
        $userid_clientid_table->create();
        $this->userid_clientid_table = $userid_clientid_table;

    }

    function getOnlineUserList(){
        if(count($this->userid_clientid_table) <= 0)
            return '';
        $userlist = '';
        foreach($this->userid_clientid_table as $userid => $client_ids)
        {
            $userlist .= $userlist ? ','.$userid : $userid;
        }
        return $userlist;
    }

    function addOnlineUserList($client_id, $userid){
        if(!$this->clientid_userid_table->exist($client_id)){
            $this->clientid_userid_table->set($client_id, array('userid' => $userid));
        }
        if(!$this->userid_clientid_table->exist($userid)){
        	$this->userid_clientid_table->set($userid, array('client_ids' => $client_id));
        }else{
        	$client_ids_info = $this->userid_clientid_table->get($userid);
        	$this->userid_clientid_table->set($userid, array('client_ids' => $client_ids_info['client_ids'].','.$client_id));
        }
            
        return true;
    }
    function getUserClientCountByUserid($userid){
    	$client_ids_info = $this->userid_clientid_table->get($userid);
    	if(!$client_ids_info)
    		return 0;
    	$client_ids = $client_ids_info['client_ids'];
    	return count(explode(',', $client_ids));
    }

    //删除客户端clientid, 返回该userid剩余clientid个数
    function delOnlineUserList($client_id, $userid){

        if($this->clientid_userid_table->exist($client_id)){
            $this->clientid_userid_table->del($client_id);
            $userid_clientid_info = $this->userid_clientid_table->get($userid);
            $client_ids = explode(',', $userid_clientid_info['client_ids']);
            $count = count($client_ids);
            if($count <= 1){
            	//只有一个用户， 则删除
            	$this->userid_clientid_table->del($userid);
            }else{
            	foreach ($client_ids as $key => $value) {
            		//只删除当前client_id
            		if($value == $client_id){
            			unset($client_ids[$key]);
            			break;
            		}
            	}
            	$this->userid_clientid_table->set($userid, array('client_ids' => implode(',', $client_ids)));

            }
            //$this->userid_clientid_table->del($userid);
            return $count - 1;
        }
    }

    /**
     * @param     $serv swoole_server
     * @param int $worker_id
     */
    function onStart($serv, $worker_id = 0)
    {
        Swoole::$php->router(array($this, 'router'));
        parent::onStart($serv, $worker_id);
    }

    function router()
    {
        var_dump($this->message);
    }

    /**
     * 进入
     * @param $client_id
     */
    function onEnter($client_id)
    {
        $this->log("onEnterline: " . $client_id);
    }

    /**
     * 下线时，通知所有人
     */
    function onExit($client_id)
    {   
        $userinfo = $this->clientid_userid_table->get($client_id);
        //将下线消息发送给所有人
        $this->log("onOffline: " . $client_id);
        unset($this->connections[$client_id]);
        $client_ids_count = $this->delOnlineUserList($client_id, $userinfo['userid']);

        //只有所有该userid都下线了， 才通知好友， 下线了
        if($client_ids_count < 1){
            //保存到数据库
            $save_data['status']      = 1;
            $model_user = model('User');
            $result = $model_user->set($userinfo['userid'], $save_data);

        	$logout_message = array('message_type'=>'logout', 'id'=>$userinfo['userid']);
        	$this->broadcast($client_id, json_encode($logout_message));
        }
        
    }

    function onMessage_mvc($client_id, $ws)
    {
        $this->log("onMessage: ".$client_id.' = '.$ws['message']);

        $this->message = $ws['message'];
        $response = Swoole::$php->runMVC();

        $this->send($client_id, $response);
        //$this->broadcast($client_id, $ws['message']);
    }

    /**
     * 接收到消息时
     */
    function onMessage($client_id, $ws)
    {
        $this->log("onMessage: ".$client_id.' = '.$ws['message']);

        // 客户端传递的是json数据
        $message_data = json_decode(($ws['message']), true);
        if(!$message_data)
        {
            return ;
        }
        switch($message_data['type'])
        {
            case 'init':
                //初始化用户。
                $init_message = array(
                    'message_type'  => $message_data['type'], 
                    'client_id'     => $client_id,
                    'online_list'   => self::getOnlineUserList()
                );
                // $this->broadcast($client_id, json_encode($login_message));
                $this->send($client_id, json_encode($init_message));
                break;
            case 'newUser':
                //添加到在线用户表
                $this->addOnlineUserList($client_id, $message_data['userInfo']['id']);
                $login_message = array(
                    'message_type' => 'newUser', 
                    'client_id' => $client_id,
                    'userid'    => $message_data['userInfo']['id'],
                    'userInfo'  => $message_data['userInfo']
                );
                $this->broadcast($client_id, json_encode($login_message));
                //$this->send($client_id, json_encode($init_message));
                break;
            case 'online':
                //添加到在线用户表
            	//查看该用户是否已经登录过, 登录过， 就不用广播。
            	$client_count = $this->getUserClientCountByUserid($message_data['userInfo']['id']);
                $this->addOnlineUserList($client_id, $message_data['userInfo']['id']);
            	if($client_count >= 1){
            		return ;
            	}
                $login_message = array(
                    'message_type' => 'online', 
                    'client_id' => $client_id,
                    'userid'    => $message_data['userInfo']['id'],
                    'userInfo'  => $message_data['userInfo']
                );
                $this->broadcast($client_id, json_encode($login_message));
                //$this->send($client_id, json_encode($init_message));
                break;
            case 'add_friend_request':
                $to_userid = $message_data['to_userid'];
                //查看该用户是否在线
                $to_user_info = $this->userid_clientid_table->get($to_userid);
                if(!$to_user_info)
                    return;
                // $to_client_id = $to_user_info['client_id'];
                $msg_box_message = array(
                    'message_type'  => 'msgbox', 
                    // 'client_id'     => $to_client_id,
                );
                $this->sendMessageByUserid($to_userid, json_encode($msg_box_message));
                // $this->send($to_client_id, json_encode($msg_box_message));
                break;
            case 'agree_friend_request':
                $to_userid  = intval($message_data['to_userid']);
                $groupid    = intval($message_data['groupid']);
                $from_user  = $message_data['from_user'];
                //查看该用户是否在线
                $to_user_info = $this->userid_clientid_table->get($to_userid);
                if(!$to_user_info)
                    return;
                // $to_client_id = $to_user_info['client_id'];
                $agree_friend_message = array(
                    'message_type'  => 'agree_friend', 
                    'groupid'       => $groupid,
                    'from_user'     => $from_user
                );
                $this->sendMessageByUserid($to_userid, json_encode($agree_friend_message));
                // $this->send($to_client_id, json_encode($agree_friend_message));
                break;
            case 'refuse_friend_request':
                $to_userid  = $message_data['to_userid'];
                //查看该用户是否在线
                $to_user_info = $this->userid_clientid_table->get($to_userid);
                if(!$to_user_info)
                    return;
                //$to_client_id = $to_user_info['client_id'];
                $refuse_friend_message = array(
                    'message_type'  => 'refuse_friend', 
                    //'client_id'     => $to_client_id,
                );
                $this->sendMessageByUserid($to_userid, json_encode($refuse_friend_message));
                // $this->send($to_client_id, json_encode($refuse_friend_message));
                break;
            case 'chatMessage':
                if(!$message_data['data']['mine']['content']){
                    return;
                }
                //群聊
                if($message_data['data']['to']['type'] == 'group'){
                        $new_message = array(
                            'message_type'  => 'chatMessage',
                            'data'          => array(
                                'from_id'       => $message_data['data']['mine']['id'],
                                'id'            => $message_data['data']['to']['id'],
                                'avatar'        => $message_data['data']['mine']['avatar'],
                                'username'      => $message_data['data']['mine']['username'],
                                'type'          => $message_data['data']['to']['type'],
                                'content'       => nl2br(htmlspecialchars($message_data['data']['mine']['content'])),
                                //'timestamp'     => getMillisecond(),
                            )
                        );
                        $this->broadcast($client_id, json_encode($new_message));
                }else{
                    //机器人聊天
                    if($message_data['data']['to']['id'] == 1){
                        $tuling_message = array(
                            'message_type'  => 'chatMessage',
                            'data'          => array(
                                'id'            => 1,
                                'username'      => '晴儿',
                                'type'          => 'friend',
                                'avatar'        => $message_data['data']['to']['avatar'],
                                'content'       => $this->getChat($message_data['data']['mine']['content']),
                                'mine'          => false,
                                'timestamp'     => getMillisecond(),
                            )
                            
                        );
                        $this->sendMessageByUserid($message_data['data']['mine']['id'], json_encode($tuling_message));
                        return;
                    }
                    $to_user_info = $this->userid_clientid_table->get($message_data['data']['to']['id']);
                    //如果对方不在线， 则保存到数据库
                    if(!$to_user_info){

                        // $not_online = array(
                        //     'type'  => 'not_online',
                        // );
                        // $this->send($client_id, json_encode($not_online));
                        //
                    }else{
                        $new_message = array(
                            'message_type'  => 'chatMessage',
                            'data'          => array(
                                'id'            => $message_data['data']['mine']['id'],
                                'avatar'        => $message_data['data']['mine']['avatar'],
                                'username'      => $message_data['data']['mine']['username'],
                                'type'          => $message_data['data']['to']['type'],
                                'content'       => nl2br(htmlspecialchars($message_data['data']['mine']['content'])),
                                'mine'          => false,
                                'timestamp'     => getMillisecond(),
                            )
                        );
                        $this->sendMessageByUserid($message_data['data']['to']['id'], json_encode($new_message));
                        // $this->send($to_user_info['client_id'], json_encode($new_message));
                    }
                }
                break;
            
            case 'inputting':
                 $to_userid  = $message_data['to_userid'];
                 $from_user  = $message_data['from_user'];
                //查看该用户是否在线
                $to_user_info = $this->userid_clientid_table->get($to_userid);
                if($to_user_info){
                    $inputting_message = array(
                        'message_type'  => 'inputting', 
                        'from_user'     => $from_user,
                    );
                    var_dump($inputting_message);
                    $this->sendMessageByUserid($to_userid, json_encode($inputting_message));
                }
                break;
            default:

        }
        //$this->send($client_id, 'Server: '.$ws['message']);
		//$this->broadcast($client_id, $ws['message']);
    }

    //发送到多客户端
    function sendMessageByclientid($clientid, $message){
    	$user_info = $this->clientid_userid_table->get($client_id);
    	$userid = $user_info['userid'];
    	//该用户下的所有client_id
    	$this->sendMessageByUserid($userid, $message);
    	return true;
    }

    function sendMessageByUserid($userid, $message){
    	$client_info = $this->userid_clientid_table->get($userid);
    	$client_ids = $client_info['client_ids'];
    	$client_list = explode(',', $client_ids);
    	foreach ($client_list as $value) {
    		$this->send($value, $message);
    	}
    	return true;
    }

    function broadcast($client_id, $msg)
    {
        foreach ($this->connections as $clid => $info)
        {
            if ($client_id != $clid)
            {
                $this->send($clid, $msg);
            }
        }
    }
    //自动回复
    public function getChat($keyword){
        //默认使用图灵机器 
        return $this->getTuling($keyword);
    }
    
    //图灵
    public function getTuling($keyword){
        $url = 'http://www.tuling123.com/openapi/api?key=a5e2b59ec45051315767be156da94e12&info='.urlencode($keyword);
        $content = $this->_curl($url);
        switch ($content['code']) {
            case 100000:
                //普通对话
                $msg = $content['text'];
                break;
            case 200000:
                //图片
                $msg = " a({$content['url']})[{$content['text']}]";
                break;
            case 308000:
                //菜谱
            default:
                $msg = '我现在还小, 等我长大后再回答你的问题';
                break;
        }
        
        return $msg;
        
    }
    public function _curl($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $txt = curl_exec($ch);
        if (curl_errno($ch)) {
            return false;
        }
        curl_close($ch);
        return json_decode($txt, true);
    }
}

function getMillisecond() {
    list($t1, $t2) = explode(' ', microtime()); 
    return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000); 
}

//require __DIR__'/phar://swoole.phar';
Swoole\Config::$debug = true;
Swoole\Error::$echo_html = false;

$AppSvr = new WebSocket();
$AppSvr->loadSetting(__DIR__."/swoole.ini"); //加载配置文件
$AppSvr->setLogger(new \Swoole\Log\EchoLog(true)); //Logger

/**
 * 如果你没有安装swoole扩展，这里还可选择
 * BlockTCP 阻塞的TCP，支持windows平台
 * SelectTCP 使用select做事件循环，支持windows平台
 * EventTCP 使用libevent，需要安装libevent扩展
 */
$enable_ssl = false;
$server = Swoole\Network\Server::autoCreate('0.0.0.0', 8282, $enable_ssl);
$server->setProtocol($AppSvr);
//$server->daemonize(); //作为守护进程
$server->run(array(
    'worker_num' => 1,
    'ssl_key_file' => __DIR__.'/ssl/ssl.key',
    'ssl_cert_file' => __DIR__.'/ssl/ssl.crt',
    //'max_request' => 1000,
    //'ipc_mode' => 2,
    //'heartbeat_check_interval' => 40,
    //'heartbeat_idle_time' => 60,
));
